package main

import (
	"fmt"
	"math"
	"reflect"
	"runtime"
)

func eval(a, b int, op string) (int, error) {

	switch op {
	case "+":
		return a + b, nil
	case "-":
		return a - b, nil
	case "*":
		return a * b, nil
	case "/":
		q, _ := div(a, b)
		return q, nil
	default:
		return 0, fmt.Errorf("unsuported operation: %s", op)
	}
}

// 13/3=4...1
//函数返回多个值的时候，可以起名字；这种只适合非常简单的情况
//对调用者没有影响
func div(a, b int) (q, r int) {
	return a / b, a % b
}

func apply(op func(int, int) int, a, b int) int {
	p := reflect.ValueOf(op).Pointer()
	opName := runtime.FuncForPC(p).Name()
	fmt.Printf("Calling function: %s with args (%d, %d) \n", opName, a, b)
	return op(a, b)
}

func power(a, b int) int {
	return int(math.Pow(float64(a), float64(b)))
}

func sum(numbers ...int) int {
	s := 0
	for i := range numbers {
		s += numbers[i]
	}
	return s
}

//这种，没用
//go里的变量都是值传递
//func swap(a, b int) {
//	a, b = b, a
//}


//这种不是很好，因为调用的时候，需要取指针
//swap(&a, &b)
//func swap(a, b *int) {
//	*a, *b = *b, *a
//}

func swap(a, b int) (int, int) {
	return b, a
}


func main() {
	//fmt.Println(eval(6, 10, "+"))
	//fmt.Println(eval(6, 10, "-"))
	//fmt.Println(eval(6, 10, "*"))
	//fmt.Println(eval(6, 10, "/"))
	//fmt.Println(eval(6, 10, "sdf"))

	if res, err := eval(6, 10, "x"); err != nil {
		fmt.Println("Error: ", err)
	} else {
		fmt.Println(res)
	}

	q, r := div(13, 3)
	fmt.Println(q, r)

	fmt.Println(apply(power, 3, 4))
	fmt.Println(apply(
		func(a, b int) int {
			return int(math.Pow(float64(a), float64(b)))
		}, 3, 4))

	fmt.Println(sum(1, 2, 3, 4, 5))

	a, b := 3, 4
	//swap(&a, &b)
	//fmt.Printf("a=%d, b=%d\n", a, b)
	a, b = swap(a, b)
	fmt.Printf("a=%d, b=%d\n", a, b)
}
